/*
 * Copyright (C) 2016, apexes.net. All rights reserved.
 * 
 *        http://www.apexes.net
 * 
 */
package net.apexes.wsonrpc.server;

import net.apexes.wsonrpc.core.ServiceRegistry;
import net.apexes.wsonrpc.core.WebSocketSession;
import net.apexes.wsonrpc.core.WsonrpcConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.ByteBuffer;

/**
 * 
 * @author <a href="mailto:hedyn@foxmail.com">HeDYn</a>
 *
 */
public class WsonrpcServerBase implements WsonrpcServer {

    private static final Logger LOG = LoggerFactory.getLogger(WsonrpcServerBase.class);

    private final WsonrpcServerEngine wsonrpcEngine;

    private WsonrpcOpenListener openListener;
    private WsonrpcCloseListener closeListener;
    private WsonrpcMessageListener messageListener;

    public WsonrpcServerBase(WsonrpcConfig config) {
        wsonrpcEngine = new WsonrpcServerEngine(config);
    }

    @Override
    public ServiceRegistry getServiceRegistry() {
        return wsonrpcEngine.getServiceRegistry();
    }

    @Override
    public void setWsonrpcOpenListener(WsonrpcOpenListener listener) {
        this.openListener = listener;
    }

    @Override
    public void setWsonrpcCloseListener(WsonrpcCloseListener listener) {
        this.closeListener = listener;
    }

    @Override
    public void setWsonrpcMessageListener(WsonrpcMessageListener listener) {
        this.messageListener = listener;
    }

    @Override
    public void setServerListener(final WsonrpcServerListener listener) {
        if (listener == null) {
            openListener = null;
            closeListener = null;
            messageListener = null;
            return;
        }

        openListener = new WsonrpcOpenListener() {
            @Override
            public void onOpened(WebSocketSession session) {
                listener.onOpen(session);
            }
        };
        closeListener = new WsonrpcCloseListener() {
            @Override
            public void onClosed(String sessionId) {
                listener.onClose(sessionId);
            }
        };
        messageListener = new WsonrpcMessageListener() {
            @Override
            public void onMessage(String sessionId, byte[] bytes) {
                listener.onMessage(sessionId, bytes);
            }
        };
    }

    @Override
    public void setWsonrpcRequestInterceptor(WsonrpcRequestInterceptor interceptor) {
        wsonrpcEngine.setWsonrpcRequestInterceptor(interceptor);
    }

    /**
     * Client端已经连接上
     * @param session
     */
    public void onOpen(WebSocketSession session) {
        WsonrpcRemotes.addRemote(session, new RemoteWsonrpcEndpoint(session, wsonrpcEngine));
        fireOpen(session);
    }

    /**
     * Client端被关闭了
     * @param sessionId
     */
    public void onClose(String sessionId) {
        WsonrpcRemotes.removeRemote(sessionId);
        fireClose(sessionId);
    }

    /**
     * 收到Client端发来的数据
     * @param sessionId
     * @param buffer
     */
    public void onMessage(String sessionId, ByteBuffer buffer) {
        try {
            WebSocketSession session = WsonrpcRemotes.getSession(sessionId);
            byte[] bytes = buffer.array();
            fireMessage(sessionId, bytes);
            wsonrpcEngine.handle(session, bytes);
        } catch (Exception ex) {
            onError(sessionId, ex);
        }
    }

    public void onError(String sessionId, Throwable error) {
        wsonrpcEngine.onError(sessionId, error);
    }
    
    private void fireOpen(WebSocketSession session) {
        LOG.debug("fireOpen : {}", session.getId());
        WsonrpcOpenListener listener = openListener;
        if (listener != null) {
            listener.onOpened(session);
        }
    }

    private void fireClose(String sessionId) {
        LOG.debug("fireClose : {}", sessionId);
        WsonrpcCloseListener listener = closeListener;
        if (listener != null) {
            listener.onClosed(sessionId);
        }
    }
    
    private void fireMessage(String sessionId, byte[] bytes) {
        LOG.debug("fireMessage : {}", sessionId);
        WsonrpcMessageListener listener = messageListener;
        if (listener != null) {
            listener.onMessage(sessionId, bytes);
        }
    }

}
